#pragma once


#include <string>

size_t GetNextPrime(size_t prime);


struct Str2D
{
public:
	size_t operator()(const std::string& s)
	{
		return SDBMHash(s.c_str());
	}
private:
	unsigned int SDBMHash(const char *str)
	{
		unsigned int hash = 0;

		while (*str)
		{
			// equivalent to: hash = 65599*hash + (*str++);
			hash = (*str++) + (hash << 6) + (hash << 16) - hash;
		}

		return (hash & 0x7FFFFFFF);
	}
};


// רŴεת
template<class T>
struct T2DDef
{
public:
	size_t operator()(const T& data)
	{
		return data;
	}
};


struct K2D1
{
public:
	size_t operator()(const std::string& s)
	{
		return SDBMHash(s.c_str());
	}
private:
	unsigned int SDBMHash(const char *str)
	{
		unsigned int hash = 0;

		while (*str)
		{
			// equivalent to: hash = 65599*hash + (*str++);
			hash = (*str++) + (hash << 6) + (hash << 16) - hash;
		}

		return (hash & 0x7FFFFFFF);
	}
};

struct K2D2
{
public:
	size_t operator()(const std::string& s)
	{
		return RSHash(s.c_str());
	}
private:
	unsigned int RSHash(const char *str)
	{
		unsigned int b = 378551;
		unsigned int a = 63689;
		unsigned int hash = 0;

		while (*str)
		{
			hash = hash * a + (*str++);
			a *= b;
		}

		return (hash & 0x7FFFFFFF);
	}
};

struct K2D3
{
public:
	size_t operator()(const std::string& s)
	{
		return JSHash(s.c_str());
	}
private:
	unsigned int JSHash(const char *str)
	{
		unsigned int hash = 1315423911;

		while (*str)
		{
			hash ^= ((hash << 5) + (*str++) + (hash >> 2));
		}

		return (hash & 0x7FFFFFFF);
	}
};

struct K2D4
{
public:
	size_t operator()(const std::string& s)
	{
		return DJBHash(s.c_str());
	}
private:
	unsigned int DJBHash(const char *str)
	{
		unsigned int hash = 5381;

		while (*str)
		{
			hash += (hash << 5) + (*str++);
		}

		return (hash & 0x7FFFFFFF);
	}
};

struct K2D5
{
public:
	size_t operator()(const std::string& s)
	{
		return ELFHash(s.c_str());
	}
private:
	unsigned int ELFHash(const char *str)
	{
		unsigned int hash = 0;
		unsigned int x = 0;

		while (*str)
		{
			hash = (hash << 4) + (*str++);
			if ((x = hash & 0xF0000000L) != 0)
			{
				hash ^= (x >> 24);
				hash &= ~x;
			}
		}

		return (hash & 0x7FFFFFFF);
	}
};